<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>Nginx 中文文档 - 在  NJS 中使用节点模块 | Docs4dev</title>
<meta charset="UTF-8">
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="Nginx (engine x) 是一个高性能的HTTP和反向代理服务，也是一个IMAP/POP3/SMTP服务。">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="HandheldFriendly" content="true">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta property="og:type" content="website">
<meta property="og:title" content="Nginx 中文文档 - 在  NJS 中使用节点模块">
<meta property="og:url" content="https://www.docs4dev.com/docs/zh/nginx/current/reference/njs-node_modules.html">
<meta property="og:site_name" content="Docs4dev">
<meta property="og:locale" content="zh_CN">
<meta name="twitter:card" content="Nginx (engine x) 是一个高性能的HTTP和反向代理服务，也是一个IMAP/POP3/SMTP服务。">
<meta name="generator" content="Docs4dev template engine">
<link rel="stylesheet" href="static/css/app.min.css">
<link rel="shortcut icon" href="https://www.docs4dev.com/static/images/favicon.ico" type="image/x-icon">
<script async="" src="static/js/js.js"></script>
<script async="" src="static/js/adsbygoogle.js" crossorigin="anonymous"></script>
<script>
    window.dataLayer = window.dataLayer || [];

    function gtag() {
      dataLayer.push(arguments);
    }

    gtag('js', new Date());
    gtag('config', 'UA-129571937-1');
  </script>
<link rel="amphtml" href="https://www.docs4dev.com/amp/docs/zh/nginx/current/reference/njs-node_modules.html">
<script type="application/ld+json">{"name":null,"headline":"Nginx 中文文档-在  NJS 中使用节点模块","inLanguage":"zh-CN","version":"current","image":"/static/icon/icon-nginx.svg","datePublished":"2021-05-20T12:51:01Z","dateCreated":"2021-05-20T12:51:01Z","dateModified":"2021-07-07T12:48:29Z","@context":"https://schema.org/","@type":"APIReference","abstract":"Nginx (engine x) 是一个高性能的HTTP和反向代理服务，也是一个IMAP/POP3/SMTP服务。"}</script>
</head>
<body>
<div class="book with-summary">
<div class="book-summary">
<div class="logo">
<a href="index.html" style="color: inherit;">
<img src="static/picture/icon-nginx.svg" style="width: 48px; height: 48px;" alt="Logo">
</a>
<b style="color: inherit; margin-left: 8px;">Nginx 中文文档</b>
</div>
<div class="item">
<div>
<label for="version">版本</label>
<select id="version" onchange="onVersionChange(this)">
<option value="current" selected="selected">current</option>
</select>
</div>
<div style="margin-top: 8px;">
<label for="language">语言</label>
<select id="language" onchange="onLangChange(this)" value="zh">
<option value="en">English</option>
<option value="zh" selected="selected">中文</option>
</select>
</div>

</div>
<div class="item menus">
<a title="Table of Contents" style="margin-right: 8px;" href="index.html">
<i class="fa fa-chevron-left"></i>
<span style="margin-left: 2px;">返回目录</span>
</a>
</div>
<nav role="navigation" id="navigation">
<ul class="summary">
<li class="chapter"> <a href="install.html" title="Introduction"> Introduction </a>
<ul class="articles">
<li class="chapter"> <a href="install.html" title="Installing nginx"> Installing nginx </a> </li>
<li class="chapter"> <a href="configure.html" title="从源代码构建  Nginx"> 从源代码构建 Nginx </a> </li>
<li class="chapter"> <a href="beginners_guide.html" title="Beginner's Guide"> Beginner's Guide </a> </li>
<li class="chapter"> <a href="control.html" title="Controlling nginx"> Controlling nginx </a> </li>
<li class="chapter"> <a href="events.html" title="连接处理方法"> 连接处理方法 </a> </li>
<li class="chapter"> <a href="hash.html" title="设置哈希"> 设置哈希 </a> </li>
<li class="chapter"> <a href="debugging_log.html" title="调试日志"> 调试日志 </a> </li>
<li class="chapter"> <a href="syslog.html" title="记录到系统日志"> 记录到系统日志 </a> </li>
<li class="chapter"> <a href="syntax.html" title="配置文件测量单位"> 配置文件测量单位 </a> </li>
<li class="chapter"> <a href="switches.html" title="Command-line parameters"> Command-line parameters </a> </li>
<li class="chapter"> <a href="windows.html" title="Windows 版  Nginx"> Windows 版 Nginx </a> </li>
<li class="chapter"> <a href="http-request_processing.html" title="Nginx 如何处理请求"> Nginx 如何处理请求 </a> </li>
<li class="chapter"> <a href="http-server_names.html" title="Server names"> Server names </a> </li>
<li class="chapter"> <a href="http-load_balancing.html" title="使用  Nginx 作为  HTTP 负载均衡器"> 使用 Nginx 作为 HTTP 负载均衡器 </a> </li>
<li class="chapter"> <a href="http-configuring_https_servers.html" title="配置  HTTPS 服务器"> 配置 HTTPS 服务器 </a> </li>
<li class="chapter"> <a href="stream-stream_processing.html" title="Nginx 如何处理  TCP/UDP 会话"> Nginx 如何处理 TCP/UDP 会话 </a> </li>
<li class="chapter"> <a href="njs-index.html" title="用  njs 编写脚本"> 用 njs 编写脚本 </a> </li>
</ul> </li>
<li class="chapter"> <a href="howto_build_on_win32.html" title="How-To"> How-To </a>
<ul class="articles">
<li class="chapter"> <a href="howto_build_on_win32.html" title="使用  Visual C 在  Win32 平台上构建  Nginx"> 使用 Visual C 在 Win32 平台上构建 Nginx </a> </li>
<li class="chapter"> <a href="nginx_dtrace_pid_provider.html" title="使用  DTrace pid 提供程序调试  nginx"> 使用 DTrace pid 提供程序调试 nginx </a> </li>
<li class="chapter"> <a href="http-converting_rewrite_rules.html" title="转换重写规则"> 转换重写规则 </a> </li>
<li class="chapter"> <a href="http-websocket.html" title="WebSocket proxying"> WebSocket proxying </a> </li>
</ul> </li>
<li class="chapter"> <a href="contributing_changes.html" title="Development"> Development </a>
<ul class="articles">
<li class="chapter"> <a href="contributing_changes.html" title="Contributing Changes"> Contributing Changes </a> </li>
<li class="chapter"> <a href="dev-development_guide.html" title="Development guide"> Development guide </a> </li>
</ul> </li>
<li class="chapter"> <a href="dirindex.html" title="Modules reference"> Modules reference </a>
<ul class="articles">
<li class="chapter"> <a href="dirindex.html" title="指令的字母索引"> 指令的字母索引 </a> </li>
<li class="chapter"> <a href="varindex.html" title="变量按字母顺序索引"> 变量按字母顺序索引 </a> </li>
<li class="chapter"> <a href="ngx_core_module.html" title="Core functionality"> Core functionality </a> </li>
<li class="chapter"> <a href="http-ngx_http_core_module.html" title="ngx_http_core_module"> ngx_http_core_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_access_module.html" title="ngx_http_access_module"> ngx_http_access_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_addition_module.html" title="ngx_http_addition_module"> ngx_http_addition_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_api_module.html" title="ngx_http_api_module"> ngx_http_api_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_auth_basic_module.html" title="ngx_http_auth_basic_module"> ngx_http_auth_basic_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_auth_jwt_module.html" title="ngx_http_auth_jwt_module"> ngx_http_auth_jwt_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_auth_request_module.html" title="ngx_http_auth_request_module"> ngx_http_auth_request_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_autoindex_module.html" title="ngx_http_autoindex_module"> ngx_http_autoindex_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_browser_module.html" title="ngx_http_browser_module"> ngx_http_browser_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_charset_module.html" title="ngx_http_charset_module"> ngx_http_charset_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_dav_module.html" title="ngx_http_dav_module"> ngx_http_dav_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_empty_gif_module.html" title="ngx_http_empty_gif_module"> ngx_http_empty_gif_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_f4f_module.html" title="ngx_http_f4f_module"> ngx_http_f4f_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_fastcgi_module.html" title="ngx_http_fastcgi_module"> ngx_http_fastcgi_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_flv_module.html" title="ngx_http_flv_module"> ngx_http_flv_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_geo_module.html" title="ngx_http_geo_module"> ngx_http_geo_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_geoip_module.html" title="ngx_http_geoip_module"> ngx_http_geoip_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_grpc_module.html" title="ngx_http_grpc_module"> ngx_http_grpc_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_gunzip_module.html" title="ngx_http_gunzip_module"> ngx_http_gunzip_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_gzip_module.html" title="ngx_http_gzip_module"> ngx_http_gzip_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_gzip_static_module.html" title="ngx_http_gzip_static_module"> ngx_http_gzip_static_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_headers_module.html" title="ngx_http_headers_module"> ngx_http_headers_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_hls_module.html" title="ngx_http_hls_module"> ngx_http_hls_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_image_filter_module.html" title="ngx_http_image_filter_module"> ngx_http_image_filter_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_index_module.html" title="ngx_http_index_module"> ngx_http_index_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_js_module.html" title="ngx_http_js_module"> ngx_http_js_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_keyval_module.html" title="ngx_http_keyval_module"> ngx_http_keyval_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_limit_conn_module.html" title="ngx_http_limit_conn_module"> ngx_http_limit_conn_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_limit_req_module.html" title="ngx_http_limit_req_module"> ngx_http_limit_req_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_log_module.html" title="ngx_http_log_module"> ngx_http_log_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_map_module.html" title="ngx_http_map_module"> ngx_http_map_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_memcached_module.html" title="ngx_http_memcached_module"> ngx_http_memcached_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_mirror_module.html" title="ngx_http_mirror_module"> ngx_http_mirror_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_mp4_module.html" title="ngx_http_mp4_module"> ngx_http_mp4_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_perl_module.html" title="ngx_http_perl_module"> ngx_http_perl_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_proxy_module.html" title="ngx_http_proxy_module"> ngx_http_proxy_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_random_index_module.html" title="ngx_http_random_index_module"> ngx_http_random_index_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_realip_module.html" title="ngx_http_realip_module"> ngx_http_realip_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_referer_module.html" title="ngx_http_referer_module"> ngx_http_referer_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_rewrite_module.html" title="ngx_http_rewrite_module"> ngx_http_rewrite_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_scgi_module.html" title="ngx_http_scgi_module"> ngx_http_scgi_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_secure_link_module.html" title="ngx_http_secure_link_module"> ngx_http_secure_link_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_session_log_module.html" title="ngx_http_session_log_module"> ngx_http_session_log_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_slice_module.html" title="ngx_http_slice_module"> ngx_http_slice_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_spdy_module.html" title="ngx_http_spdy_module"> ngx_http_spdy_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_split_clients_module.html" title="ngx_http_split_clients_module"> ngx_http_split_clients_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_ssi_module.html" title="ngx_http_ssi_module"> ngx_http_ssi_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_ssl_module.html" title="ngx_http_ssl_module"> ngx_http_ssl_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_status_module.html" title="ngx_http_status_module"> ngx_http_status_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_stub_status_module.html" title="ngx_http_stub_status_module"> ngx_http_stub_status_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_sub_module.html" title="ngx_http_sub_module"> ngx_http_sub_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_upstream_module.html" title="ngx_http_upstream_module"> ngx_http_upstream_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_upstream_conf_module.html" title="ngx_http_upstream_conf_module"> ngx_http_upstream_conf_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_upstream_hc_module.html" title="ngx_http_upstream_hc_module"> ngx_http_upstream_hc_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_userid_module.html" title="ngx_http_userid_module"> ngx_http_userid_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_uwsgi_module.html" title="ngx_http_uwsgi_module"> ngx_http_uwsgi_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_v2_module.html" title="ngx_http_v2_module"> ngx_http_v2_module </a> </li>
<li class="chapter"> <a href="http-ngx_http_xslt_module.html" title="ngx_http_xslt_module"> ngx_http_xslt_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_core_module.html" title="ngx_mail_core_module"> ngx_mail_core_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_auth_http_module.html" title="ngx_mail_auth_http_module"> ngx_mail_auth_http_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_proxy_module.html" title="ngx_mail_proxy_module"> ngx_mail_proxy_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_ssl_module.html" title="ngx_mail_ssl_module"> ngx_mail_ssl_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_imap_module.html" title="ngx_mail_imap_module"> ngx_mail_imap_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_pop3_module.html" title="ngx_mail_pop3_module"> ngx_mail_pop3_module </a> </li>
<li class="chapter"> <a href="mail-ngx_mail_smtp_module.html" title="ngx_mail_smtp_module"> ngx_mail_smtp_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_core_module.html" title="ngx_stream_core_module"> ngx_stream_core_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_access_module.html" title="ngx_stream_access_module"> ngx_stream_access_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_geo_module.html" title="ngx_stream_geo_module"> ngx_stream_geo_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_geoip_module.html" title="ngx_stream_geoip_module"> ngx_stream_geoip_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_js_module.html" title="ngx_stream_js_module"> ngx_stream_js_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_keyval_module.html" title="ngx_stream_keyval_module"> ngx_stream_keyval_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_limit_conn_module.html" title="ngx_stream_limit_conn_module"> ngx_stream_limit_conn_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_log_module.html" title="ngx_stream_log_module"> ngx_stream_log_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_map_module.html" title="ngx_stream_map_module"> ngx_stream_map_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_proxy_module.html" title="ngx_stream_proxy_module"> ngx_stream_proxy_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_realip_module.html" title="ngx_stream_realip_module"> ngx_stream_realip_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_return_module.html" title="ngx_stream_return_module"> ngx_stream_return_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_split_clients_module.html" title="ngx_stream_split_clients_module"> ngx_stream_split_clients_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_ssl_module.html" title="ngx_stream_ssl_module"> ngx_stream_ssl_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_ssl_preread_module.html" title="ngx_stream_ssl_preread_module"> ngx_stream_ssl_preread_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_upstream_module.html" title="ngx_stream_upstream_module"> ngx_stream_upstream_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_upstream_hc_module.html" title="ngx_stream_upstream_hc_module"> ngx_stream_upstream_hc_module </a> </li>
<li class="chapter"> <a href="stream-ngx_stream_zone_sync_module.html" title="ngx_stream_zone_sync_module"> ngx_stream_zone_sync_module </a> </li>
<li class="chapter"> <a href="ngx_google_perftools_module.html" title="ngx_google_perftools_module"> ngx_google_perftools_module </a> </li>
</ul> </li>
</ul>
</nav>
</div>
<div class="book-body">
<div class="body-inner">
<header class="book-header">
<div class="dropdown pull-right js-toolbar-action">
<a class="btn toggle-dropdown" aria-label="Language" href="#">
<i class="fa fa-globe"></i>
</a>
<div class="dropdown-menu dropdown-left">
<div class="dropdown-caret"><span class="caret-outer"></span><span class="caret-inner"></span></div>
<div class="buttons">
<button class="button size-1" onclick="changeLang('zh_CN')">中文</button>
</div>
<div class="buttons">
<button class="button size-1" onclick="changeLang('en_US')">English</button>
</div>
</div>
</div>
<a class="btn pull-right js-toolbar-action non-mobile" aria-label="Sign up" href="register.html">
<i class="fa fa-sign-in"></i> <span>注册</span>
</a>
<a class="btn pull-right js-toolbar-action non-mobile" aria-label="Sign in" href="register.html">
<i class="fa fa-sign-in"></i>
<span>登录</span>
</a>
<a class="btn pull-left js-toolbar-action btn-summary" href="#"><i class="fa fa-align-justify"></i></a>
<div class="dropdown pull-left font-settings js-toolbar-action">
<a class="btn toggle-dropdown" aria-label="Font Settings" href="#">
<i class="fa fa-font"></i>
</a>
<div class="dropdown-menu dropdown-right">
<div class="dropdown-caret"><span class="caret-outer"></span><span class="caret-inner"></span></div>
<div class="buttons">
<button class="button size-2 font-reduce">A</button>
<button class="button size-2 font-enlarge">A</button>
</div>
<div class="buttons">
<button class="button size-2 family-serif">Serif</button>
<button class="button size-2 family-sans">Sans</button>
</div>
<div class="buttons">
<button class="button size-3 theme-white">White</button>
<button class="button size-3 theme-sepia">Sepia</button>
<button class="button size-3 theme-night">Night</button>
</div>
</div>
</div>
<a class="btn pull-left js-toolbar-action non-mobile" aria-label="Home" href="zh.html">
<i class="fa fa-home"></i> <span>首页</span>
</a>
<a class="btn pull-left js-toolbar-action non-mobile" aria-label="Guide" href="javascript:window.open('https://www.javadoc.org/');">
<i class="fa fa-book"></i> <span>API Docs</span>
</a>
<a class="btn pull-left js-toolbar-action non-mobile" aria-label="Tools" href="index1.html">
<i class="fa fa-gears"></i> <span>工具</span>
</a>
<div class="dropdown pull-left js-toolbar-action mobile">
<a class="btn toggle-dropdown" aria-label="Language" href="#">
<i class="fa fa-chevron-down"></i>
</a>
<div class="dropdown-menu dropdown-right">
<div class="dropdown-caret"><span class="caret-outer"></span><span class="caret-inner"></span></div>
<div class="buttons">
<a class="button size-1" aria-label="Home" href="zh.html">
<i class="fa fa-home"></i> <span>首页</span>
</a>
</div>
<div class="buttons">
<a class="button size-1" aria-label="Guide" href="javascript:window.open('https://www.javadoc.org/');">
<i class="fa fa-book"></i> <span>API Docs</span>
</a>
</div>
<div class="buttons">
<a class="button size-1" aria-label="Tools" href="index1.html">
<i class="fa fa-gears"></i> <span>工具</span>
</a>
</div>
</div>
</div>
<div id="autocomplete" class="pull-right"></div>
<span id="toolbar-title"></span>
</header>
<div class="page-wrapper" tabindex="-1" role="main">
<div class="page-inner">
<section class="normal markdown-section">
<div id="content">
<h1>在 NJS 中使用节点模块</h1>
<div><ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid" data-ad-client="ca-pub-6108808167664152" data-ad-slot="6964403648"></ins>
<script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
<div><ul>
<li><a href="#intro">Introduction</a></li>
<li><a href="#environment">Environment</a></li>
<li><a href="#protobuf">Protobufjs</a></li>
<li><a href="#dnspacket">DNS-packet</a><br><a href="" id="intro"></a></li>
</ul>
<h4 id="introduction"><a href="#introduction" id="introduction"></a>Introduction</h4>
<p>通常，开发人员想使用第三方代码，通常以某种形式的库形式提供。在 Javascript 世界中，模块的概念相对较新，因此直到最近才出现标准。许多平台(浏览器)仍然不支持模块，这使得代码重用变得更加困难。 njs 还不支持模块。本文以<a href="javascript:window.open('https://nodejs.org/');" target="_blank" rel="noopener noreferrer">Node.js</a>生态系统为例，介绍了克服此限制的方法。</p>
<div class="alert callout info"><p class="title"><i class="fa fa-info-circle"></i>Note</p><div><p>本文中的示例使用的是<a href="njs-index.html">njs</a> <a href="njs-changes.html#njs0.3.8">0.3.8</a>中出现的功能</p>
</div></div>
<p>将第三方代码添加到 njs 时，可能会出现许多问题：</p>
<ul>
<li>
<p>相互引用的多个文件及其依赖性</p>
</li>
<li>
<p>Platform-specific APIs</p>
</li>
<li>
<p>现代标准语言结构</p>
</li>
</ul>
<p>好消息是，这些问题不是 njs 的新问题或特定问题。当试图支持具有完全不同特性的多个不同平台时，JavaScript 开发人员每天都会面对它们。有些工具旨在解决上述问题。</p>
<ul>
<li>相互引用的多个文件及其依赖性</li>
</ul>
<p>这可以通过将所有相互依赖的代码合并到一个文件中来解决。 <a href="javascript:window.open('http://browserify.org/');" target="_blank" rel="noopener noreferrer">browserify</a>或<a href="javascript:window.open('https://webpack.js.org/');" target="_blank" rel="noopener noreferrer">webpack</a>之类的工具可以接受整个项目，并生成一个包含您的代码和所有依赖项的文件。</p>
<ul>
<li>Platform-specific APIs</li>
</ul>
<p>您可以使用多个以平台无关的方式实现此类 API 的库(但是以性能为代价)。还可以使用<a href="javascript:window.open('https://polyfill.io/v3/');" target="_blank" rel="noopener noreferrer">polyfill</a>方法实现特定功能。</p>
<ul>
<li>现代标准语言结构</li>
</ul>
<p>可以编译这样的代码：这意味着执行许多转换，以根据较旧的标准重写较新的语言功能。例如，<a href="javascript:window.open('https://babeljs.io/');" target="_blank" rel="noopener noreferrer">babel</a>项目可用于此目的。</p>
<p>在本指南中，我们将使用两个相对较大的 npm 托管库：</p>
<ul>
<li>
<p><a href="javascript:window.open('https://www.npmjs.com/package/protobufjs');" target="_blank" rel="noopener noreferrer">protobufjs</a>-一个用于创建和解析<a href="javascript:window.open('https://grpc.io/');" target="_blank" rel="noopener noreferrer">gRPC</a>协议使用的 protobuf 消息的库。</p>
</li>
<li>
<p><a href="javascript:window.open('https://www.npmjs.com/package/dns-packet');" target="_blank" rel="noopener noreferrer">dns-packet</a>-用于处理 DNS 协议数据包的库。</p>
</li>
</ul>
<p><a href="" id="environment"></a></p>
<h4 id="environment"><a href="#environment" id="environment"></a>Environment</h4>
<div class="alert callout info"><p class="title"><i class="fa fa-info-circle"></i>Note</p><div><p>本文档主要采用通用方法以及有关 Node.js 和快速 Developing 的 JavaScript 生态系统的 AVOIDS 特定的最佳实践建议。在执行此处建议的步骤之前，请确保先查阅相应的包装手册。</p>
</div></div>
<p>首先(假设 Node.js 已安装且可运行)，让我们创建一个空项目并安装一些依赖项。下面的命令假定我们在工作目录中：</p>
<pre><code class="hljs language-shell">$ mkdir my_project &amp;&amp; cd my_project
$ npx license choose_your_license_here &gt; LICENSE
$ npx gitignore node

$ cat &gt; package.json &lt;&lt;EOF
{
  &quot;name&quot;:        &quot;foobar&quot;,
  &quot;version&quot;:     &quot;0.0.1&quot;,
  &quot;description&quot;: &quot;&quot;,
  &quot;main&quot;:        &quot;index.js&quot;,
  &quot;keywords&quot;:    [],
  &quot;author&quot;:      &quot;somename &lt;<a href="email-protection.html" class="__cf_email__" data-cfemail="394a56545c175c54585055795c41585449555c175a5654">[email&#160;protected]</a>&gt; (https://example.com)&quot;,
  &quot;license&quot;:     &quot;some_license_here&quot;,
  &quot;private&quot;:     true,
  &quot;scripts&quot;: {
    &quot;test&quot;: &quot;echo \&quot;Error: no test specified\&quot; &amp;&amp; exit 1&quot;
  }
}
EOF
$ npm init -y
$ npm install browserify
</code></pre>
<p><a href="" id="protobuf"></a></p>
<h4 id="protobufjs"><a href="#protobufjs" id="protobufjs"></a>Protobufjs</h4>
<p>该库提供了用于<code>.proto</code>接口定义的解析器以及用于消息解析和生成的代码生成器。</p>
<p>在此示例中，我们将使用 gRPC 示例中的<a href="javascript:window.open('https://github.com/grpc/grpc/blob/master/examples/protos/helloworld.proto');" target="_blank" rel="noopener noreferrer">helloworld.proto</a>文件。我们的目标是创建两个消息：<code>HelloRequest</code>和<code>HelloResponse</code>。我们将使用 protobufjs 的<a href="javascript:window.open('https://github.com/protobufjs/protobuf.js/blob/master/README.md#reflection-vs-static-code');" target="_blank" rel="noopener noreferrer">static</a>模式，而不是动态生成类，因为出于安全考虑，njs 不支持动态添加新功能。</p>
<p>接下来，安装该库，并从协议定义中生成实现消息编组的 javascript 代码：</p>
<pre><code class="hljs language-shell">$ npm install protobufjs
$ npx pbjs -t static-module helloworld.proto &gt; static.js
</code></pre>
<p>因此，<code>static.js</code>文件成为我们的新依赖项，其中存储了实现消息处理所需的所有代码。 <code>set_buffer()</code>函数包含使用该库创建带有序列化<code>HelloRequest</code>消息的缓冲区的代码。该代码位于<code>code.js</code>文件中：</p>
<pre><code class="hljs language-shell">var pb = require('./static.js');

// Example usage of protobuf library: prepare a buffer to send
function set_buffer(pb)
{
    // set fields of gRPC payload
    var payload = { name: &quot;TestString&quot; };

    // create an object
    var message = pb.helloworld.HelloRequest.create(payload);

    // serialize object to buffer
    var buffer = pb.helloworld.HelloRequest.encode(message).finish();

    var n = buffer.length;

    var frame = new Uint8Array(5 + buffer.length);

    frame[0] = 0;                        // 'compressed' flag
    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // length: uint32 in network order
    frame[2] = (n &amp; 0x00FF0000) &gt;&gt;&gt; 16;
    frame[3] = (n &amp; 0x0000FF00) &gt;&gt;&gt;  8;
    frame[4] = (n &amp; 0x000000FF) &gt;&gt;&gt;  0;

    frame.set(buffer, 5);

    return frame;
}

var frame = set_buffer(pb);
</code></pre>
<p>为了确保其正常工作，我们使用 node 执行代码：</p>
<pre><code class="hljs language-shell">$ node ./code.js
Uint8Array [
    0,   0,   0,   0,  12, 10,
   10,  84, 101, 115, 116, 83,
  116, 114, 105, 110, 103
]
</code></pre>
<p>您可以看到，这为我们提供了正确编码的<code>gRPC</code>帧。现在让我们用 njs 运行它：</p>
<pre><code class="hljs language-shell">$ njs ./code.js
Thrown:
Error: Cannot find module &quot;./static.js&quot;
    at require (native)
    at main (native)
</code></pre>
<p>不支持模块，因此我们收到了异常。要解决此问题，请使用<code>browserify</code>或其他类似工具。</p>
<p>尝试处理我们现有的<code>code.js</code>文件将导致一堆 JS 代码在浏览器中运行，即在加载后立即运行。这不是我们 true 想要的东西。相反，我们希望有一个可以从 nginx 配置中引用的导出函数。这需要一些包装器代码。</p>
<div class="alert callout info"><p class="title"><i class="fa fa-info-circle"></i>Note</p><div><p>在本指南中，为简单起见，我们在所有示例中均使用 njs cli。在现实生活中，您将使用 nginx njs 模块来运行代码。</p>
</div></div>
<p><code>load.js</code>文件包含将其句柄存储在全局名称空间中的库加载代码：</p>
<pre><code class="hljs language-shell">global.hello = require('./static.js');
</code></pre>
<p>此代码将被合并的内容替换。我们的代码将使用“ <code>global.hello</code>”句柄访问该库。</p>
<p>接下来，我们使用 browserify 处理它，以将所有依赖关系放入一个文件中：</p>
<pre><code class="hljs language-shell">$ npx browserify load.js -o bundle.js -d
</code></pre>
<p>结果是包含我们所有依赖项的巨大文件：</p>
<pre><code class="hljs language-shell">(function(){function......
...
...
},{&quot;protobufjs/minimal&quot;:9}]},{},[1])
//# sourceMappingURL..............
</code></pre>
<p>为了获得最终的“ <code>njs_bundle.js</code>”文件，我们将“ <code>bundle.js</code>”和以下代码连接在一起：</p>
<pre><code class="hljs language-shell">// Example usage of protobuf library: prepare a buffer to send
function set_buffer(pb)
{
    // set fields of gRPC payload
    var payload = { name: &quot;TestString&quot; };

    // create an object
    var message = pb.helloworld.HelloRequest.create(payload);

    // serialize object to buffer
    var buffer = pb.helloworld.HelloRequest.encode(message).finish();

    var n = buffer.length;

    var frame = new Uint8Array(5 + buffer.length);

    frame[0] = 0;                        // 'compressed' flag
    frame[1] = (n &amp; 0xFF000000) &gt;&gt;&gt; 24;  // length: uint32 in network order
    frame[2] = (n &amp; 0x00FF0000) &gt;&gt;&gt; 16;
    frame[3] = (n &amp; 0x0000FF00) &gt;&gt;&gt;  8;
    frame[4] = (n &amp; 0x000000FF) &gt;&gt;&gt;  0;

    frame.set(buffer, 5);

    return frame;
}

// functions to be called from outside
function setbuf()
{
    return set_buffer(global.hello);
}

// call the code
var frame = setbuf();
console.log(frame);
</code></pre>
<p>让我们使用 node 运行文件，以确保一切正常：</p>
<pre><code class="hljs language-shell">$ node ./njs_bundle.js
Uint8Array [
    0,   0,   0,   0,  12, 10,
   10,  84, 101, 115, 116, 83,
  116, 114, 105, 110, 103
]
</code></pre>
<p>现在让我们 continue 使用 njs：</p>
<pre><code class="hljs language-shell">$ /njs ./njs_bundle.js
Uint8Array [0,0,0,0,12,10,10,84,101,115,116,83,116,114,105,110,103]
</code></pre>
<p>最后一件事是使用特定于 njs 的 API 将数组转换为字节字符串，因此它可以被 nginx 模块使用。我们可以在最后一行之前添加以下代码段：</p>
<pre><code class="hljs language-shell">if (global.njs) {
    return String.bytesFrom(frame)
}
</code></pre>
<p>最后，我们使其工作：</p>
<pre><code class="hljs language-shell">$ njs ./njs_bundle.js |hexdump -C
00000000  00 00 00 00 0c 0a 0a 54  65 73 74 53 74 72 69 6e  |.......TestStrin|
00000010  67 0a                                             |g.|
00000012
</code></pre>
<p>这是预期的结果。响应解析可以类似地实现：</p>
<pre><code class="hljs language-shell">function parse_msg(pb, msg)
{
    // convert byte string into integer array
    var bytes = msg.split('').map(v=&gt;v.charCodeAt(0));

    if (bytes.length &lt; 5) {
        throw 'message too short';
    }

    // first 5 bytes is gRPC frame (compression + length)
    var head = bytes.splice(0, 5);

    // ensure we have proper message length
    var len = (head[1] &lt;&lt; 24)
              + (head[2] &lt;&lt; 16)
              + (head[3] &lt;&lt; 8)
              + head[4];

    if (len != bytes.length) {
        throw 'header length mismatch';
    }

    // invoke protobufjs to decode message
    var response = pb.helloworld.HelloReply.decode(bytes);

    console.log('Reply is:' + response.message);
}
</code></pre>
<p><a href="" id="dnspacket"></a></p>
<h4 id="dns-packet"><a href="#dns-packet" id="dns-packet"></a>DNS-packet</h4>
<p>本示例使用一个库来生成和解析 DNS 数据包。这种情况值得考虑，因为该库及其依赖项使用了 njs 尚不支持的现代语言构造。反过来，这要求我们采取额外的步骤：编译源代码。</p>
<p>需要其他节点程序包：</p>
<pre><code class="hljs language-shell">$ npm install @babel/core @babel/cli @babel/preset-env babel-loader
$ npm install webpack webpack-cli
$ npm install buffer
$ npm install dns-packet
</code></pre>
<p>配置文件 webpack.config.js：</p>
<pre><code class="hljs language-shell">const path = require('path');

module.exports = {
    entry: './load.js',
    mode: 'production',
    output: {
        filename: 'wp_out.js',
        path: path.resolve(__dirname, 'dist'),
    },
    optimization: {
        minimize: false
    },
    node: {
        global: true,
    },
    module : {
        rules: [{
            test: /\.m?js$$/,
            exclude: /(bower_components)/,
            use: {
                loader: 'babel-loader',
                options: {
                    presets: ['@babel/preset-env']
                }
            }
        }]
    }
};
</code></pre>
<p>请注意，我们使用的是“ <code>production</code>”模式。在这种模式下，webpack 不使用 njs 不支持的“ <code>eval</code>”构造。引用的<code>load.js</code>文件是我们的入口点：</p>
<pre><code class="hljs language-shell">global.dns = require('dns-packet')
global.Buffer = require('buffer/').Buffer
</code></pre>
<p>我们以相同的方式开始，为库生成一个文件：</p>
<pre><code class="hljs language-shell">$ npx browserify load.js -o bundle.js -d
</code></pre>
<p>接下来，我们使用 webpack 处理文件，而 webpack 本身会调用 babel：</p>
<pre><code class="hljs language-shell">$ npx webpack --config webpack.config.js
</code></pre>
<p>此命令产生<code>dist/wp_out.js</code>文件，该文件是<code>bundle.js</code>的转译版本。我们需要将其与存储代码的<code>code.js</code>连接起来：</p>
<pre><code class="hljs language-shell">function set_buffer(dnsPacket)
{
    // create DNS packet bytes
    var buf = dnsPacket.encode({
        type: 'query',
        id: 1,
        flags: dnsPacket.RECURSION_DESIRED,
        questions: [{
            type: 'A',
            name: 'google.com'
        }]
    })

    return buf;
}
</code></pre>
<p>请注意，在此示例中，生成的代码未包装到函数中，因此我们无需显式调用它。结果在“ <code>dist</code>”目录中：</p>
<pre><code class="hljs language-shell">$ cat dist/wp_out.js code.js &gt; njs_dns_bundle.js
</code></pre>
<p>让我们在文件末尾调用我们的代码：</p>
<pre><code class="hljs language-shell">var b = setbuf(1);
console.log(b);
</code></pre>
<p>并使用 node 执行它：</p>
<pre><code class="hljs language-shell">$ node ./njs_dns_bundle_final.js
Buffer [Uint8Array] [
    0,   1,   1, 0,  0,   1,   0,   0,
    0,   0,   0, 0,  6, 103, 111, 111,
  103, 108, 101, 3, 99, 111, 109,   0,
    0,   1,   0, 1
]
</code></pre>
<p>确保这可以按预期工作，然后使用 njs 运行它：</p>
<pre><code class="hljs language-shell">$ njs ./njs_dns_bundle_final.js
Uint8Array [0,1,1,0,0,1,0,0,0,0,0,0,6,103,111,111,103,108,101,3,99,111,109,0,0,1,0,1]
</code></pre>
<p>响应可以解析如下：</p>
<pre><code class="hljs language-shell">function parse_response(buf)
{
    var bytes = buf.split('').map(v=&gt;v.charCodeAt(0));

    var b = global.Buffer.from(bytes);

    var packet = dnsPacket.decode(b);

    var resolved_name = packet.answers[0].name;

    // expected name is 'google.com', according to our request above
}
</code></pre>
</div>
</div>
</section>
<div class="right-sidebar">
<div class="affix"><ins class="adsbygoogle" style="display:block" data-ad-client="ca-pub-6108808167664152" data-ad-slot="3102929424" data-ad-format="auto" data-full-width-responsive="true"></ins>
<script data-cfasync="false" src="static/js/email-decode.min.js"></script><script>
     (adsbygoogle = window.adsbygoogle || []).push({});
</script></div>
</div>
</div>
<div class="ft">
<a href="#toolbar-title" id="anchorNavigationExGoTop"><i class="fa fa-arrow-up"></i></a>
<footer class="footer">
<div class="footer__container--normal">
<img alt="扫码关注公众号" title="扫码关注公众号" src="static/picture/qr-code.png" width="170" height="170">
<div class="footer__description--normal">
<p class="paragraph footer__author--normal">Docs4dev<sup class="super">&#xAE;</sup>
</p>
<p class="paragraph footer__quote&#45;&#45;normal">
如果你在使用过程中遇到任何问题，可以在 <a href="javascript:window.open('https://github.com/docs4dev/docs4dev-issues');" target="_blank" rel="noopener noreferrer">这里<i class="fa fa-external-link"></i></a> 提issue。
</p>
<div class="footer__main--normal">
<p class="paragraph footer__main__paragraph--normal copyright" style="color: #666 !important;">
<a href="javascript:window.open('https://beian.miit.gov.cn/');">
 蜀ICP备14021783号-6
</a>
</p>
<p class="paragraph footer__main__paragraph--normal copyright" style="color: #666 !important;">
Copyright &#xA9; Docs4dev all
right reserved, powered by <a href="index2.html" target="_blank">Docs4dev</a></p>
</div>
</div>
</div>
<div class="box__issues">
</div>
</footer>
</div>
</div>
</div>
</div>
</div>
<script>
  var hasToc = true;
  /*  var downloadable = /!*false*!/ false;
    var editable = /!*false*!/ false;
    var code = /!*"nginx"*!/ false;
    var version = /!*"current"*!/ false;
    var type = /!*"reference"*!/ false;
    var lang = /!*"zh"*!/ 'en';
    //edit link
    require(["gitbook", "jQuery"], function (gitbook, $) {
      gitbook.events.bind('start', function (e, config) {
        // Add edit toolbar to left
        var chapterId = /!*17764*!/ 0;
        if (downloadable) {
          gitbook.toolbar.createButton({
            icon: 'fa fa-download',
            text: '下载',
            onClick: function () {
              window.open('/download?code=' + code + '&version=' + version + '&type=' + type + '&lang=' + lang);
            }
          });
        }
        if (editable) {
          gitbook.toolbar.createButton({
            icon: 'fa fa-edit',
            text: '编辑此页',
            onClick: function () {
              window.open('/docs/edit?chapterId=' + chapterId + '&lang=' + lang);
            }
          });
        }
      });
    });*/
</script>
<script>
    var code = "nginx";
    var lang = "zh";
  </script>

<script src="static/js/autocomplete-js.js"></script>
<script src="static/js/app.min.js"></script>
<script src="static/js/search.min.js"></script>
</body>
</html>
